package com.smartum.mpr.services;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.imageio.ImageIO;

import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.smartum.mpr.business.UploadedImageBusiness;
import com.smartum.mpr.business.UserBusiness;
import com.smartum.mpr.exception.NotExistsImageException;
import com.smartum.mpr.exception.NotExistsUserException;
import com.smartum.mpr.model.UploadedImage;
import com.smartum.mpr.model.UploadedImageClassy;
import com.smartum.mpr.model.UploadedImageComment;
import com.smartum.mpr.model.UploadedImageGangster;
import com.smartum.mpr.model.UploadedImageLike;
import com.smartum.mpr.model.UploadedImageOdd;
import com.smartum.mpr.model.UploadedImageSexy;
import com.smartum.mpr.model.UploadedImageStatus;
import com.smartum.mpr.model.UploadedImageType;
import com.smartum.mpr.model.User;
import com.smartum.mpr.store.local.UserImageStoreProvider;
import com.smartum.mpr.util.BackendConfig;
import com.smartum.mpr.utils.ImageUtil;

@Controller
@RequestMapping(value = "/photo")
public class ImageService extends BaseService<UploadedImage> {

	@Autowired
	private UploadedImageBusiness imageBusiness;
	@Autowired
	private UserBusiness userBusiness;

	@RequestMapping(method = RequestMethod.POST, value = "/post")
	public ResponseEntity<String> postImage(@RequestParam(value = "photo") MultipartFile file, @RequestParam(
	        value = "json") String json) {
		LOGGER_API.info("request: add photo - " + json);
		LOGGER_API.info("request: add photo - file name" + file.getOriginalFilename());
		LOGGER_API.info("request: add photo - file size" + file.getSize());
		try {
			String appFolderPath = BackendConfig.getInstance().getAppFolder();

			String token = extractTokenStringData(json);
			UploadedImage image = new UploadedImage();
			image.setImagePath("stub");
			image.setLittleImagePath("stub");
			image.setStatus(UploadedImageStatus.NOT_MODERATED);
			image.setImageTimestamp(System.currentTimeMillis());
			imageBusiness.addImage(token, image);

			String filePath = (new UserImageStoreProvider()).storeImage(file, image.getId());
			File imageFile = new File(appFolderPath + filePath);
			BufferedImage littleImage = ImageUtil.resizeImage(imageFile, 200, 200);

			String smallImagePath = ImageUtil.addPostfixToPhotoWithSupportFileFormat(filePath, "small");
			File smallPhotoFile = new File(appFolderPath + smallImagePath);

			ImageIO.write(littleImage, ImageUtil.getImageFormat(smallImagePath), smallPhotoFile);

			image.setLittleImagePath(smallImagePath);
			image.setImagePath(filePath);
			imageBusiness.addImage(token, image);

			imageBusiness.updateImageToResponse(image);

			image.setComments(new HashSet<UploadedImageComment>());

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson(getTargetParser().writeEntity(image)), HttpStatus.OK);
			LOGGER_API.info("response : add photo   - OK");
			logResponse(response);

			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : add photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/get/user")
	public ResponseEntity<String> getUserPhotos(@RequestBody String json) {
		LOGGER_API.info("request: get user photos - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long timestamp = requestRootNode.get("timestamp").asLong();
			int amount = requestRootNode.get("amount").asInt();

			User user = null;

			if(requestRootNode.get("user_id")==null){
				String token = extractTokenStringData(json);
				user = userBusiness.getUserByToken(token);
			}else{
				checkRequestPermissions(json);
				long userId = requestRootNode.get("user_id").asLong();
				user = userBusiness.getById(userId);
			}

			if(user==null){
				throw new NotExistsUserException();
			}

			List<UploadedImage> images = imageBusiness.getUserUploadedImages(user.getId(), amount, timestamp);
			partitionCommentsSet(images);

			ResponseEntity<String> response = getResponseInJsonType(generateSuccessJson(getTargetParser()
			        .writeEntityList(images)), HttpStatus.OK);
			LOGGER_API.info("response :get user photos   - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : get user photos ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/get/public")
	public ResponseEntity<String> getPublicPhotos(@RequestBody String json) {
		LOGGER_API.info("request: get public photos - " + json);
		try {
			LOGGER_API.info("Llego el request de /get/public");
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);
			LOGGER_API.info("Llego 1");
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long timestamp = requestRootNode.get("timestamp").asLong();
			int amount = requestRootNode.get("amount").asInt();
			LOGGER_API.info("Llego 2");
			Long userId = 0l;
			try {
				LOGGER_API.info("Llego 3");
				String token = extractTokenStringData(json);
				User user = userBusiness.getUserByToken(token);
				if (user != null) {
					userId = user.getId();
				}
			} catch (NullPointerException e) {
				LOGGER_API.info("Error NullPointerException:" + e.toString());
			}

			LOGGER_API.info("Llego 4");
			List<UploadedImage> images = imageBusiness.getPublicUploadedImages(timestamp, amount, userId);
			partitionCommentsSet(images);

			LOGGER_API.info("Llego 5");
			ResponseEntity<String> response = getResponseInJsonType(generateSuccessJson(getTargetParser()
			        .writeEntityList(images)), HttpStatus.OK);

			LOGGER_API.info("Llego 6");
			LOGGER_API.info("response : get public photos  - OK");
			logResponse(response);

			return response;
		} catch (Exception e) {
			LOGGER_API.info("Error fatal:" + e.toString());
			LOGGER_API.error("response : get public photos ", e);
			return handleException(e);
		}
	}
	//Like
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/like/add")
	public ResponseEntity<String> addPhotoStarLike(@RequestBody String json) {
		LOGGER_API.info("request: add star like for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addLikeForPhoto(token, photoId);

			LOGGER_API.info("response : add star like for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star like for photo ", e);
			return handleException(e);
		}
	}
	@RequestMapping(method = RequestMethod.POST, value = "/like/delete")
	public ResponseEntity<String> deletePhotoStarLike(@RequestBody String json) {
		LOGGER_API.info("request: delete star like for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteLikeForPhoto(token, photoId);

			LOGGER_API.info("response : delete star for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star for photo ", e);
			return handleException(e);
		}
	}

	//Sexy
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/sexy/add")
	public ResponseEntity<String> addPhotoStarSexy(@RequestBody String json) {
		LOGGER_API.info("request: add star sexy for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addSexyForPhoto(token, photoId);

			LOGGER_API.info("response : add star sexy for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star sexy for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/sexy/delete")
	public ResponseEntity<String> deletePhotoStarSexy(@RequestBody String json) {
		LOGGER_API.info("request: delete star sexy for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteSexyForPhoto(token, photoId);

			LOGGER_API.info("response : delete star sexy for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star sexy for photo ", e);
			return handleException(e);
		}
	}

	//Gangster
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/gangster/add")
	public ResponseEntity<String> addPhotoStarGangster(@RequestBody String json) {
		LOGGER_API.info("request: add star gangster for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addGangsterForPhoto(token, photoId);

			LOGGER_API.info("response : add star gangster for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star gangster for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/gangster/delete")
	public ResponseEntity<String> deletePhotoStarGangster(@RequestBody String json) {
		LOGGER_API.info("request: delete star gangster for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteGangsterForPhoto(token, photoId);

			LOGGER_API.info("response : delete star gangster for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star gangster for photo ", e);
			return handleException(e);
		}
	}

	//Odd
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/odd/add")
	public ResponseEntity<String> addPhotoStarOdd(@RequestBody String json) {
		LOGGER_API.info("request: add star odd for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addOddForPhoto(token, photoId);

			LOGGER_API.info("response : add star odd for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star odd for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/odd/delete")
	public ResponseEntity<String> deletePhotoStarOdd(@RequestBody String json) {
		LOGGER_API.info("request: delete star odd for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteOddForPhoto(token, photoId);

			LOGGER_API.info("response : delete star odd for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star odd for photo ", e);
			return handleException(e);
		}
	}
	//Hoax
		//*****************************
		@RequestMapping(method = RequestMethod.POST, value = "/hoax/add")
		public ResponseEntity<String> addPhotoStarHoax(@RequestBody String json) {
			LOGGER_API.info("request: add star hoax for photo - " + json);
			try {
				String request = extractRequestStringData(json);
				String token = extractTokenStringData(json);

				ObjectMapper mapper = getTargetParser().getMapper();
				JsonNode requestRootNode = mapper.readTree(request);

				Long photoId = requestRootNode.get("photo_id").asLong();

				imageBusiness.addHoaxForPhoto(token, photoId);

				LOGGER_API.info("response : add star hoax for photo  - OK");
				return new ResponseEntity<String>(HttpStatus.OK);
			} catch (Exception e) {
				LOGGER_API.error("response : add star hoax for photo ", e);
				return handleException(e);
			}
		}

		@RequestMapping(method = RequestMethod.POST, value = "/hoax/delete")
		public ResponseEntity<String> deletePhotoStarHoax(@RequestBody String json) {
			LOGGER_API.info("request: delete star hoax for photo - " + json);
			try {
				String request = extractRequestStringData(json);
				String token = extractTokenStringData(json);

				ObjectMapper mapper = getTargetParser().getMapper();
				JsonNode requestRootNode = mapper.readTree(request);

				Long photoId = requestRootNode.get("photo_id").asLong();

				imageBusiness.deleteHoaxForPhoto(token, photoId);

				LOGGER_API.info("response : delete star hoax for photo  - OK");
				return new ResponseEntity<String>(HttpStatus.OK);
			} catch (Exception e) {
				LOGGER_API.error("response : delete star hoax for photo ", e);
				return handleException(e);
			}
		}
	//Type
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/type/add")
	public ResponseEntity<String> addPhotoStarType(@RequestBody String json) {
		LOGGER_API.info("request: add star type for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addTypeForPhoto(token, photoId);

			LOGGER_API.info("response : add star type for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star type for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/type/delete")
	public ResponseEntity<String> deletePhotoStarType(@RequestBody String json) {
		LOGGER_API.info("request: delete star type for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteTypeForPhoto(token, photoId);

			LOGGER_API.info("response : delete star type for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star type for photo ", e);
			return handleException(e);
		}
	}

	//Sad
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/sad/add")
	public ResponseEntity<String> addPhotoStarSad(@RequestBody String json) {
		LOGGER_API.info("request: add star sad for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addSadForPhoto(token, photoId);

			LOGGER_API.info("response : add star sad for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star sad for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/sad/delete")
	public ResponseEntity<String> deletePhotoStarsad(@RequestBody String json) {
		LOGGER_API.info("request: delete star sad for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteSadForPhoto(token, photoId);

			LOGGER_API.info("response : delete star sad for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star sad for photo ", e);
			return handleException(e);
		}
	}

	//Classy
	//*****************************
	@RequestMapping(method = RequestMethod.POST, value = "/classy/add")
	public ResponseEntity<String> addPhotoStarArtistic(@RequestBody String json) {
		LOGGER_API.info("request: add star classy for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.addClassyForPhoto(token, photoId);

			LOGGER_API.info("response : add star classy for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add star classy for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/classy/delete")
	public ResponseEntity<String> deletePhotoStarArtistic(@RequestBody String json) {
		LOGGER_API.info("request: delete star artistic for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();

			imageBusiness.deleteClassyForPhoto(token, photoId);

			LOGGER_API.info("response : delete star artistic for photo  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : delete star artistic for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/comment/add")
	public ResponseEntity<String> addComment(@RequestBody String json) {
		LOGGER_API.info("request: add comment for photo - " + json);
		try {
			String request = extractRequestStringData(json);
			String token = extractTokenStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();
			String comment = requestRootNode.get("comment").asText();

			UploadedImageComment commentObject = imageBusiness.addCommentForPhoto(token, comment, photoId);

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageComment.class)).writeEntity(commentObject)),
			        HttpStatus.OK);
			LOGGER_API.info("response : add comment for photo   - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : add comment for photo ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/comment/get")
	public ResponseEntity<String> getPhotoComments(@RequestBody String json) {
		LOGGER_API.info("request: get photo comments - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageComment> comments = imageBusiness.getUploadedImageComments(photoId);

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageComment.class)).writeEntityList(comments)),
			        HttpStatus.OK);
			LOGGER_API.info("response :get photo comments - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : get photo comments ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/like/get")
	public ResponseEntity<String> getPhotoLikes(@RequestBody String json) {
		LOGGER_API.info("request: get photo likes - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageLike> likes = new ArrayList<UploadedImageLike>();
			likes.addAll(imageBusiness.getUploadedImageLikes(photoId));

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageLike.class).writeEntityList(likes))),
			        HttpStatus.OK);
			LOGGER_API.info("response : get photo likes    - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : get photo likes  ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/sexy/get")
	public ResponseEntity<String> getPhotoSexys(@RequestBody String json) {
		LOGGER_API.info("request: get photo sexys - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageSexy> sexys = new ArrayList<UploadedImageSexy>();
			sexys.addAll(imageBusiness.getUploadedImageSexys(photoId));

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageSexy.class).writeEntityList(sexys))),
			        HttpStatus.OK);
			LOGGER_API.info("response : get photo sexys    - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : get photo sexys  ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/classy/get")
	public ResponseEntity<String> getPhotoClassys(@RequestBody String json) {
		LOGGER_API.info("request: get photo classy - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageClassy> classys = new ArrayList<UploadedImageClassy>();
			classys.addAll(imageBusiness.getUploadedImageClassys(photoId));

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageClassy.class).writeEntityList(classys))),
			        HttpStatus.OK);
			LOGGER_API.info("response : get photo classy    - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : get photo classy  ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/odd/get")
	public ResponseEntity<String> getPhotoOdds(@RequestBody String json) {
		LOGGER_API.info("request: get photo odd - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageOdd> odds = new ArrayList<UploadedImageOdd>();
			odds.addAll(imageBusiness.getUploadedImageOdds(photoId));

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageOdd.class).writeEntityList(odds))),
			        HttpStatus.OK);
			LOGGER_API.info("response : get photo odd    - OK");
			logResponse(response);
			return response;
		} catch (Exception e) {
			LOGGER_API.error("response : get photo odd  ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/type/get")
	public ResponseEntity<String> getPhotoTypes(@RequestBody String json) {
		LOGGER_API.info("request: get photo type - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageType> types = new ArrayList<UploadedImageType>();
			types.addAll(imageBusiness.getUploadedImageTypes(photoId));

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageType.class).writeEntityList(types))),
			        HttpStatus.OK);
			LOGGER_API.info("response : get photo type    - OK");
			logResponse(response);
			return response;
		} catch (Exception e){
			LOGGER_API.error("response : get photo type  ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/gangster/get")
	public ResponseEntity<String> getPhotoGangster(@RequestBody String json) {
		LOGGER_API.info("request: get photo gangster - " + json);
		try {
			checkRequestPermissions(json);
			String request = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);
			Long photoId = requestRootNode.get("photo_id").asLong();

			List<UploadedImageGangster> gangsters = new ArrayList<UploadedImageGangster>();
			gangsters.addAll(imageBusiness.getUploadedImageGangster(photoId));

			ResponseEntity<String> response = getResponseInJsonType(
			        generateSuccessJson((getParserByEntityClass(UploadedImageGangster.class).writeEntityList(gangsters))),
			        HttpStatus.OK);
			LOGGER_API.info("response : get photo gangster    - OK");
			logResponse(response);
			return response;
		} catch (Exception e){
			LOGGER_API.error("response : get photo gangster  ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/delete")
	public ResponseEntity<String> removeImageById(@RequestBody String json) {
		LOGGER_API.info("request: remove image - " + json);
		try {
			extractTokenStringData(json);
			String requestJsonBody = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			Long imageID = mapper.readTree(requestJsonBody).get("photo_id").asLong();

			UploadedImage image = imageBusiness.getUploadedImageById(imageID);
			if (image != null) {
				(new UserImageStoreProvider()).deleteImage(imageID);
			} else {
				throw new NotExistsImageException("not exists image with id:" + imageID);
			}

			imageBusiness.removeImageById(imageID);
			LOGGER_API.info("response : remove image  by id - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : remove image by id", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/get/unconfirmed")
	public ResponseEntity<String> getUnconfirmedImages(@RequestBody String json) {
		LOGGER_API.info("request: get unconfirmed images - " + json);
		try {
			checkRequestPermissions(json);

			String requestJsonBody = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			long timestamp = mapper.readTree(requestJsonBody).get("timestamp").asLong();
			int amount = mapper.readTree(requestJsonBody).get("amount").asInt();

			List<UploadedImage> images = imageBusiness.getUnconfirnedImages(timestamp, amount);
			long unconfirmedImagesCount = imageBusiness.getUnconfirnedImagesNumber();

			ObjectNode node = getTargetParser().getMapper().createObjectNode();
			node.put("unconfirmed_images_number", unconfirmedImagesCount);
			node.put("images", getTargetParser().writeEntityList(images));

			ResponseEntity<String> responseEntity = getResponseInJsonType(
			        generateSuccessJson(mapper.writeValueAsString(node)), HttpStatus.OK);

			LOGGER_API.info("response : get unconfirmed images  - OK");
			logResponse(responseEntity);
			return responseEntity;
		} catch (Exception e) {
			LOGGER_API.error("response : get unconfirmed images ", e);
			return handleException(e);
		}
	}

	@RequestMapping(method = RequestMethod.POST, value = "/moderation")
	public ResponseEntity<String> imagesModeration(@RequestBody String json) {
		LOGGER_API.info("request: images moderation - " + json);
		try {
			checkRequestPermissions(json);

			String requestJsonBody = extractRequestStringData(json);

			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode rootNode = mapper.readTree(requestJsonBody);

			Long[] confirmedIds = getTargetParser().getMapper().readValue(rootNode.get("confirmed"), Long[].class);
			if (confirmedIds.length > 0) {
				imageBusiness.confirmImages(confirmedIds);
			}

			Long[] unconfirmedIds = getTargetParser().getMapper().readValue(rootNode.get("unconfirmed"), Long[].class);
			if (unconfirmedIds.length > 0) {
				imageBusiness.declineImages(unconfirmedIds);
			}

			LOGGER_API.info("response : images moderation  - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : images moderation  ", e);
			return handleException(e);
		}
	}


	@RequestMapping(method = RequestMethod.POST, value = "/flag")
	public ResponseEntity<String> flagPhoto(@RequestBody String json) {
		LOGGER_API.info("request: add photo flag - " + json);
		try {
			checkRequestPermissions(json);

			String request = extractRequestStringData(json);
			ObjectMapper mapper = getTargetParser().getMapper();
			JsonNode requestRootNode = mapper.readTree(request);

			Long photoId = requestRootNode.get("photo_id").asLong();
			imageBusiness.addFlagToImage(photoId);

			LOGGER_API.info("response : add photo flag   - OK");
			return new ResponseEntity<String>(HttpStatus.OK);
		} catch (Exception e) {
			LOGGER_API.error("response : add photo flag ", e);
			return handleException(e);
		}
	}

	@Override
	protected Class<UploadedImage> getEntityClass() {
		return UploadedImage.class;
	}

	private void partitionCommentsSet(List<UploadedImage> images) {
		for (UploadedImage image : images) {
			Set<UploadedImageComment> allImageComments = image.getComments();
			Set<UploadedImageComment> newComments = new TreeSet<UploadedImageComment>(
			        UploadedImageComment.ascendingUploadedImageComparator);
			List<UploadedImageComment> commentsList = new ArrayList<UploadedImageComment>();
			commentsList.addAll(allImageComments);

			Collections.sort(commentsList, UploadedImageComment.ascendingUploadedImageComparator);

			int k = 0;
			if (commentsList.size() > 0) {
				for (int i = commentsList.size() - 1; i >= 0; i--) {
					if (k < 5) {
						newComments.add(commentsList.get(i));
					}
					k++;
				}
				image.setComments(newComments);
			}
		}
	}

}
